using System;
using Kaleida.ServiceMonitor.Framework;
using Kaleida.ServiceMonitor.Framework.Responses;

namespace Kaleida.ServiceMonitor.Operations.ResponseHandlers
{
    public class MustBeLessThan : ResponseHandler
    {
        private readonly string expectedLimit;

        public MustBeLessThan(string expectedLimit)
        {
            this.expectedLimit = expectedLimit;
        }

        public override string Description
        {
            get { return string.Format("expect less than {0}", expectedLimit); }
        }

        public override string ProcessResponse(object response)
        {
            if (response is int && expectedLimit.IsInteger())
            {
                var actualInt = (int)response;
                TestAsInteger(actualInt);
                return actualInt.ToFormattedString();
            }
            if (response is decimal && expectedLimit.IsDecimal())
            {
                var actualDecimal = (decimal)response;
                TestAsDecimal(actualDecimal);
                return actualDecimal.ToFormattedString();
            }
            if (response is TimeSpan && expectedLimit.IsTimeSpan())
            {
                var actualTimespan = (TimeSpan)response;
                TestAsTimespan(actualTimespan);
                return actualTimespan.ToFormattedString();
            }
            if (response is ITimedEvent && expectedLimit.IsTimeSpan())
            {
                var actualTimespan = ((ITimedEvent)response).TimeTaken;
                TestAsTimespan(actualTimespan);
                return "Time Taken " + actualTimespan.ToFormattedString();
            }
            throw new InvalidOperationException(string.Format("Cannot perform '{0}' < '{1}' with string values", response, expectedLimit));
        }

        private void TestAsTimespan(TimeSpan actualTimespan)
        {
            var expectedTimespan = expectedLimit.ToTimeSpan();

            if (actualTimespan >= expectedTimespan)
                throw NewMismatchException(expectedTimespan.ToFormattedString(), actualTimespan.ToFormattedString());
        }

        private void TestAsDecimal(decimal actualDecimal)
        {
            var expectedDecimal = Convert.ToDecimal(expectedLimit);

            if (actualDecimal >= expectedDecimal)
                throw NewMismatchException(expectedDecimal.ToFormattedString(), actualDecimal.ToFormattedString());
        }

        private void TestAsInteger(int actualInt)
        {
            var expectedInt = Convert.ToInt32(expectedLimit);

            if (actualInt >= expectedInt)
                throw NewMismatchException(expectedInt.ToFormattedString(), actualInt.ToFormattedString());
        }

        private static InvalidOperationException NewMismatchException(object expectedLimit, object response)
        {
            return new InvalidOperationException(string.Format("Expected response to be less than {0} but was {1}", expectedLimit, response));
        }
    }
}